package http

import (
	"github.com/edgexfoundry/edgex-go/internal/app/core/metadata/application"
	"github.com/edgexfoundry/edgex-go/internal/app/core/metadata/controller"
	"github.com/edgexfoundry/edgex-go/internal/app/dtos/requests"
	responseDTO "github.com/edgexfoundry/edgex-go/internal/app/dtos/responses"
	"github.com/edgexfoundry/edgex-go/internal/io"
	"github.com/edgexfoundry/edgex-go/internal/pkg"
	"github.com/edgexfoundry/edgex-go/internal/pkg/correlation"
	"github.com/edgexfoundry/edgex-go/internal/pkg/utils"
	"github.com/edgexfoundry/go-mod-bootstrap/v2/bootstrap/container"
	"github.com/edgexfoundry/go-mod-bootstrap/v2/di"
	"github.com/edgexfoundry/go-mod-core-contracts/v2/common"
	commonDTO "github.com/edgexfoundry/go-mod-core-contracts/v2/dtos/common"
	"github.com/google/uuid"
	"github.com/gorilla/mux"
	"math"
	"net/http"
)

type DeviceCommandController struct {
	reader io.DtoReader
	dic    *di.Container
}

// NewDeviceCommandController creates and initializes an DeviceCommandController
func NewDeviceCommandController(dic *di.Container) *DeviceCommandController {
	return &DeviceCommandController{
		reader: io.NewJsonDtoReader(),
		dic:    dic,
	}
}

func (dc *DeviceCommandController) DeviceCommandAdd(w http.ResponseWriter, r *http.Request) {
	if r.Body != nil {
		defer func() { _ = r.Body.Close() }()
	}

	lc := container.LoggingClientFrom(dc.dic.Get)
	ctx := r.Context()
	correlationId := correlation.FromContext(ctx)

	// URL parameters
	vars := mux.Vars(r)
	deviceId := vars[common.DeviceId]

	var reqDTOs requests.CommandAddRequest
	err := dc.reader.Read(r.Body, &reqDTOs)
	if err != nil {
		utils.WriteErrorResponse(w, ctx, lc, err, "")
		return
	}

	var response interface{}
	reqId := reqDTOs.RequestId
	deviceCommand := reqDTOs.Command.ToDeviceCommandModel()

	// 新增设备功能时，增加uuid属性值
	uid, _ := uuid.NewUUID()
	deviceCommand.Id = uid.String()

	err = application.DeviceCommandAdd(deviceId, deviceCommand, ctx, dc.dic)
	if err != nil {
		lc.Error(err.Error(), common.CorrelationHeader, correlationId)
		lc.Debug(err.DebugMessages(), common.CorrelationHeader, correlationId)
		response = commonDTO.NewBaseResponse(
			reqId,
			err.Message(),
			err.Code())
	} else {
		response = commonDTO.NewBaseResponse(
			reqId,
			"",
			http.StatusCreated)
	}

	utils.WriteHttpHeader(w, ctx, http.StatusMultiStatus)
	pkg.EncodeAndWriteResponse(response, w, lc)
}

func (dc *DeviceCommandController) DeviceCommandGet(w http.ResponseWriter, r *http.Request) {
	lc := container.LoggingClientFrom(dc.dic.Get)
	ctx := r.Context()

	// URL parameters
	vars := mux.Vars(r)
	deviceId := vars[common.DeviceId]

	page, err := utils.ParseQueryStringToInt(r, controller.Page, common.DefaultOffset, 0, math.MaxInt32)
	if err != nil {
		page = 0
	}
	pageSize, err := utils.ParseQueryStringToInt(r, controller.PageSize, common.DefaultLimit, 0, math.MaxInt32)
	if err != nil {
		pageSize = math.MaxInt32
	}

	commands, totalCount, err := application.DeviceCommandGet(deviceId, page*pageSize, pageSize, ctx, dc.dic)
	if err != nil {
		utils.WriteErrorResponse(w, ctx, lc, err, "")
		return
	}

	response := responseDTO.NewDeviceCommandResponse("", "", http.StatusOK, commands, page, pageSize, totalCount)
	utils.WriteHttpHeader(w, ctx, http.StatusOK)
	pkg.EncodeAndWriteResponse(response, w, lc)
}

func (dc *DeviceCommandController) DeviceCommandDelete(w http.ResponseWriter, r *http.Request) {
	lc := container.LoggingClientFrom(dc.dic.Get)
	ctx := r.Context()

	// URL parameters
	vars := mux.Vars(r)
	deviceId := vars[common.DeviceId]
	// URL parameters
	id := utils.ParseQueryStringToString(r, controller.Id, "")

	err := application.DeviceCommandDelete(deviceId, id, ctx, dc.dic)
	if err != nil {
		utils.WriteErrorResponse(w, ctx, lc, err, "")
		return
	}

	response := commonDTO.NewBaseResponse("", "", http.StatusOK)
	utils.WriteHttpHeader(w, ctx, http.StatusOK)
	pkg.EncodeAndWriteResponse(response, w, lc)
}

func (dc *DeviceCommandController) DeviceCommandUpdate(w http.ResponseWriter, r *http.Request) {
	lc := container.LoggingClientFrom(dc.dic.Get)
	ctx := r.Context()

	// URL parameters
	vars := mux.Vars(r)
	deviceId := vars[common.DeviceId]

	var reqDTOs requests.CommandUpdateRequest
	err := dc.reader.Read(r.Body, &reqDTOs)
	if err != nil {
		utils.WriteErrorResponse(w, ctx, lc, err, "")
		return
	}

	deviceCommand := reqDTOs.Command.ToDeviceCommandModel()
	err = application.DeviceCommandUpdate(deviceId, deviceCommand, ctx, dc.dic)

	if err != nil {
		utils.WriteErrorResponse(w, ctx, lc, err, "")
		return
	}
	response := commonDTO.NewBaseResponse("", "", http.StatusOK)
	utils.WriteHttpHeader(w, ctx, http.StatusOK)
	pkg.EncodeAndWriteResponse(response, w, lc)
}
